using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using System.Text.RegularExpressions;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Infrastructure.CmsDbContext;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 通知管理服务实现
    /// </summary>
    public class NotificationService : INotificationService
    {
        private readonly LowCodeDbContext _context;
        private readonly ILogger<NotificationService> _logger;

        public NotificationService(
            LowCodeDbContext context,
            ILogger<NotificationService> logger)
        {
            _context = context;
            _logger = logger;
        }

        // =============================
        // 通知发送
        // =============================

        public async Task<NotificationRecord> SendNotificationAsync(string tenantId, string notificationType, string recipient, string subject, string content, Dictionary<string, object>? metadata = null)
        {
            try
            {
                var record = new NotificationRecord
                {
                    TenantId = tenantId,
                    NotificationType = notificationType,
                    Recipient = recipient,
                    Subject = subject,
                    Content = content,
                    Status = "pending",
                    Priority = 5,
                    Metadata = metadata != null ? JsonSerializer.Serialize(metadata) : null,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };

                _context.NotificationRecords.Add(record);
                await _context.SaveChangesAsync();

                // 异步处理发送
                _ = Task.Run(async () => await ProcessNotificationAsync(record.Id));

                return record;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error sending notification to {Recipient}", recipient);
                throw;
            }
        }

        public async Task<NotificationRecord> SendTemplateNotificationAsync(string tenantId, string templateCode, string recipient, Dictionary<string, object> variables, Dictionary<string, object>? metadata = null)
        {
            try
            {
                var template = await GetTemplateAsync(tenantId, templateCode);
                if (template == null)
                {
                    throw new InvalidOperationException($"Template not found: {templateCode}");
                }

                var subject = ReplaceVariables(template.Subject ?? "", variables);
                var content = ReplaceVariables(template.Content, variables);

                var record = new NotificationRecord
                {
                    TenantId = tenantId,
                    NotificationType = template.NotificationType,
                    TemplateId = template.Id,
                    Recipient = recipient,
                    Subject = subject,
                    Content = content,
                    Status = "pending",
                    Priority = 5,
                    Metadata = metadata != null ? JsonSerializer.Serialize(metadata) : null,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };

                _context.NotificationRecords.Add(record);
                await _context.SaveChangesAsync();

                // 异步处理发送
                _ = Task.Run(async () => await ProcessNotificationAsync(record.Id));

                return record;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error sending template notification {TemplateCode} to {Recipient}", templateCode, recipient);
                throw;
            }
        }

        public async Task<List<NotificationRecord>> SendBatchNotificationAsync(string tenantId, string templateCode, List<string> recipients, Dictionary<string, object> variables)
        {
            var records = new List<NotificationRecord>();

            foreach (var recipient in recipients)
            {
                try
                {
                    var record = await SendTemplateNotificationAsync(tenantId, templateCode, recipient, variables);
                    records.Add(record);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error in batch notification for recipient {Recipient}", recipient);
                }
            }

            return records;
        }

        public async Task<NotificationRecord> ScheduleNotificationAsync(string tenantId, string templateCode, string recipient, Dictionary<string, object> variables, DateTime scheduledAt)
        {
            var template = await GetTemplateAsync(tenantId, templateCode);
            if (template == null)
            {
                throw new InvalidOperationException($"Template not found: {templateCode}");
            }

            var subject = ReplaceVariables(template.Subject ?? "", variables);
            var content = ReplaceVariables(template.Content, variables);

            var record = new NotificationRecord
            {
                TenantId = tenantId,
                NotificationType = template.NotificationType,
                TemplateId = template.Id,
                Recipient = recipient,
                Subject = subject,
                Content = content,
                Status = "scheduled",
                Priority = 5,
                ScheduledAt = scheduledAt,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            _context.NotificationRecords.Add(record);
            await _context.SaveChangesAsync();

            return record;
        }

        // =============================
        // 模板管理
        // =============================

        public async Task<NotificationTemplate> CreateTemplateAsync(string tenantId, string name, string code, string notificationType, string subject, string content, Dictionary<string, object>? variables = null)
        {
            var template = new NotificationTemplate
            {
                TenantId = tenantId,
                Name = name,
                Code = code,
                NotificationType = notificationType,
                Subject = subject,
                Content = content,
                Variables = variables != null ? JsonSerializer.Serialize(variables) : null,
                IsEnabled = true,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            _context.NotificationTemplates.Add(template);
            await _context.SaveChangesAsync();
            return template;
        }

        public async Task<NotificationTemplate?> UpdateTemplateAsync(long templateId, string? name = null, string? subject = null, string? content = null, Dictionary<string, object>? variables = null)
        {
            var template = await _context.NotificationTemplates.FindAsync(templateId);
            if (template == null) return null;

            if (!string.IsNullOrEmpty(name)) template.Name = name;
            if (subject != null) template.Subject = subject;
            if (!string.IsNullOrEmpty(content)) template.Content = content;
            if (variables != null) template.Variables = JsonSerializer.Serialize(variables);

            template.Version++;
            template.UpdatedAt = DateTime.UtcNow;

            await _context.SaveChangesAsync();
            return template;
        }

        public async Task<NotificationTemplate?> GetTemplateAsync(string tenantId, string code)
        {
            return await _context.NotificationTemplates
                .FirstOrDefaultAsync(t => t.TenantId == tenantId && t.Code == code && t.IsEnabled);
        }

        public async Task<List<NotificationTemplate>> GetTemplatesAsync(string tenantId, string? notificationType = null, bool? isEnabled = null)
        {
            var query = _context.NotificationTemplates.Where(t => t.TenantId == tenantId);

            if (!string.IsNullOrEmpty(notificationType))
                query = query.Where(t => t.NotificationType == notificationType);

            if (isEnabled.HasValue)
                query = query.Where(t => t.IsEnabled == isEnabled.Value);

            return await query.OrderByDescending(t => t.CreatedAt).ToListAsync();
        }

        public async Task<bool> DeleteTemplateAsync(long templateId)
        {
            var template = await _context.NotificationTemplates.FindAsync(templateId);
            if (template == null) return false;

            template.IsEnabled = false;
            template.UpdatedAt = DateTime.UtcNow;
            await _context.SaveChangesAsync();
            return true;
        }

        // =============================
        // 配置管理
        // =============================

        public async Task<TenantNotificationConfig> CreateConfigAsync(string tenantId, string notificationType, string channel, Dictionary<string, object> configuration)
        {
            var config = new TenantNotificationConfig
            {
                TenantId = tenantId,
                NotificationType = notificationType,
                Channel = channel,
                Configuration = JsonSerializer.Serialize(configuration),
                IsEnabled = true,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            _context.TenantNotificationConfigs.Add(config);
            await _context.SaveChangesAsync();
            return config;
        }

        public async Task<TenantNotificationConfig?> UpdateConfigAsync(long configId, bool? isEnabled = null, Dictionary<string, object>? configuration = null)
        {
            var config = await _context.TenantNotificationConfigs.FindAsync(configId);
            if (config == null) return null;

            if (isEnabled.HasValue) config.IsEnabled = isEnabled.Value;
            if (configuration != null) config.Configuration = JsonSerializer.Serialize(configuration);
            config.UpdatedAt = DateTime.UtcNow;

            await _context.SaveChangesAsync();
            return config;
        }

        public async Task<List<TenantNotificationConfig>> GetConfigsAsync(string tenantId, string? notificationType = null)
        {
            var query = _context.TenantNotificationConfigs.Where(c => c.TenantId == tenantId);

            if (!string.IsNullOrEmpty(notificationType))
                query = query.Where(c => c.NotificationType == notificationType);

            return await query.OrderBy(c => c.Priority).ToListAsync();
        }

        public async Task<bool> DeleteConfigAsync(long configId)
        {
            var config = await _context.TenantNotificationConfigs.FindAsync(configId);
            if (config == null) return false;

            _context.TenantNotificationConfigs.Remove(config);
            await _context.SaveChangesAsync();
            return true;
        }

        // =============================
        // 订阅管理
        // =============================

        public async Task<NotificationSubscription> CreateSubscriptionAsync(string tenantId, string userId, string eventType, string notificationType, string frequency = "immediate")
        {
            var subscription = new NotificationSubscription
            {
                TenantId = tenantId,
                UserId = userId,
                EventType = eventType,
                NotificationType = notificationType,
                Frequency = frequency,
                IsEnabled = true,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };

            _context.NotificationSubscriptions.Add(subscription);
            await _context.SaveChangesAsync();
            return subscription;
        }

        public async Task<NotificationSubscription?> UpdateSubscriptionAsync(long subscriptionId, bool? isEnabled = null, string? frequency = null)
        {
            var subscription = await _context.NotificationSubscriptions.FindAsync(subscriptionId);
            if (subscription == null) return null;

            if (isEnabled.HasValue) subscription.IsEnabled = isEnabled.Value;
            if (!string.IsNullOrEmpty(frequency)) subscription.Frequency = frequency;
            subscription.UpdatedAt = DateTime.UtcNow;

            await _context.SaveChangesAsync();
            return subscription;
        }

        public async Task<List<NotificationSubscription>> GetUserSubscriptionsAsync(string tenantId, string userId)
        {
            return await _context.NotificationSubscriptions
                .Where(s => s.TenantId == tenantId && s.UserId == userId)
                .OrderBy(s => s.EventType)
                .ToListAsync();
        }

        public async Task<bool> DeleteSubscriptionAsync(long subscriptionId)
        {
            var subscription = await _context.NotificationSubscriptions.FindAsync(subscriptionId);
            if (subscription == null) return false;

            _context.NotificationSubscriptions.Remove(subscription);
            await _context.SaveChangesAsync();
            return true;
        }

        // =============================
        // 记录查询
        // =============================

        public async Task<List<NotificationRecord>> GetNotificationRecordsAsync(string tenantId, string? status = null, DateTime? startDate = null, DateTime? endDate = null, int page = 1, int pageSize = 20)
        {
            var query = _context.NotificationRecords.Where(r => r.TenantId == tenantId);

            if (!string.IsNullOrEmpty(status))
                query = query.Where(r => r.Status == status);

            if (startDate.HasValue)
                query = query.Where(r => r.CreatedAt >= startDate.Value);

            if (endDate.HasValue)
                query = query.Where(r => r.CreatedAt <= endDate.Value);

            return await query
                .OrderByDescending(r => r.CreatedAt)
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .Include(r => r.Template)
                .ToListAsync();
        }

        public async Task<Dictionary<string, long>> GetNotificationStatisticsAsync(string tenantId, DateTime? startDate = null, DateTime? endDate = null)
        {
            var query = _context.NotificationRecords.Where(r => r.TenantId == tenantId);

            if (startDate.HasValue)
                query = query.Where(r => r.CreatedAt >= startDate.Value);

            if (endDate.HasValue)
                query = query.Where(r => r.CreatedAt <= endDate.Value);

            var stats = await query
                .GroupBy(r => r.Status)
                .Select(g => new { Status = g.Key, Count = g.Count() })
                .ToDictionaryAsync(x => x.Status, x => (long)x.Count);

            return stats;
        }

        public async Task<bool> RetryNotificationAsync(long recordId)
        {
            var record = await _context.NotificationRecords.FindAsync(recordId);
            if (record == null || record.Status == "sent") return false;

            record.Status = "pending";
            record.RetryCount++;
            record.LastRetryAt = DateTime.UtcNow;
            record.UpdatedAt = DateTime.UtcNow;

            await _context.SaveChangesAsync();

            // 异步处理重试
            _ = Task.Run(async () => await ProcessNotificationAsync(recordId));

            return true;
        }

        public async Task<bool> CancelScheduledNotificationAsync(long recordId)
        {
            var record = await _context.NotificationRecords.FindAsync(recordId);
            if (record == null || record.Status != "scheduled") return false;

            record.Status = "cancelled";
            record.UpdatedAt = DateTime.UtcNow;

            await _context.SaveChangesAsync();
            return true;
        }

        // =============================
        // 私有辅助方法
        // =============================

        private async Task ProcessNotificationAsync(long recordId)
        {
            try
            {
                var record = await _context.NotificationRecords.FindAsync(recordId);
                if (record == null || record.Status != "pending") return;

                // 获取配置
                var configs = await GetConfigsAsync(record.TenantId, record.NotificationType);
                var activeConfig = configs.FirstOrDefault(c => c.IsEnabled);

                if (activeConfig == null)
                {
                    record.Status = "failed";
                    record.ErrorMessage = "No active configuration found";
                    await _context.SaveChangesAsync();
                    return;
                }

                // 模拟发送（实际实现中这里会调用具体的发送服务）
                var success = await SimulateSendNotification(record, activeConfig);

                if (success)
                {
                    record.Status = "sent";
                    record.SentAt = DateTime.UtcNow;
                    record.ExternalMessageId = Guid.NewGuid().ToString();
                }
                else
                {
                    record.Status = "failed";
                    record.ErrorMessage = "Send operation failed";
                }

                record.UpdatedAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing notification {RecordId}", recordId);
            }
        }

        private async Task<bool> SimulateSendNotification(NotificationRecord record, TenantNotificationConfig config)
        {
            // 模拟延迟
            await Task.Delay(100);

            // 模拟90%成功率
            return Random.Shared.NextDouble() > 0.1;
        }

        private static string ReplaceVariables(string template, Dictionary<string, object> variables)
        {
            if (string.IsNullOrEmpty(template) || variables == null || variables.Count == 0)
                return template;

            var result = template;
            foreach (var variable in variables)
            {
                var pattern = $@"\{{\{{\s*{Regex.Escape(variable.Key)}\s*\}}\}}";
                result = Regex.Replace(result, pattern, variable.Value?.ToString() ?? "");
            }

            return result;
        }
    }
}
